import os
import json
import subprocess
import logging
import keyboard
from pathlib import Path
import time
import win32gui
import win32con
import win32api
import win32process

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler('eclipse_jumper.log')
    ]
)

# 配置参数
CURSOR_STATE_FILE = os.path.expanduser("~/.eclipse-cursor-sync-plugin/cursor_editor_state.json")
ECLIPSE_STATE_FILE = os.path.expanduser("~/.eclipse/editor_state.json")
ECLIPSE_PATH = r"D:\eclipse2024\jee-2024-12\eclipse\eclipse.exe"  # 使用原始字符串避免转义问题
CURSOR_PATH = r"C:\Users\ThinkPad\AppData\Local\Programs\cursor\Cursor.exe"  # Cursor可执行文件路径

def check_eclipse_path():
    """检查Eclipse路径是否存在"""
    if not os.path.exists(ECLIPSE_PATH):
        logging.error(f"未找到Eclipse，路径: {ECLIPSE_PATH}")
        return False
    return True

def validate_state(state):
    """验证状态数据是否有效"""
    required_fields = ["file_path", "line_number"]
    if not all(field in state for field in required_fields):
        logging.error(f"状态格式无效。缺少必要字段: {required_fields}")
        return False
    
    if not os.path.exists(state["file_path"]):
        logging.error(f"文件未找到: {state['file_path']}")
        return False
    
    try:
        line_number = int(state["line_number"])
        if line_number < 1:
            logging.error(f"无效的行号: {line_number}")
            return False
    except ValueError:
        logging.error(f"无效的行号格式: {state['line_number']}")
        return False
    
    # 检查列号（如果存在）
    if "column" in state:
        try:
            column = int(state["column"])
            if column < 1:
                logging.error(f"无效的列号: {column}")
                return False
        except ValueError:
            logging.error(f"无效的列号格式: {state['column']}")
            return False
    
    return True

def get_file_timestamp(file_path):
    """获取文件的最后修改时间戳"""
    try:
        return os.path.getmtime(file_path)
    except Exception as e:
        logging.error(f"获取文件时间戳失败: {str(e)}")
        return 0

def find_cursor_window():
    """查找Cursor窗口句柄"""
    def callback(hwnd, windows):
        if win32gui.IsWindowVisible(hwnd):
            title = win32gui.GetWindowText(hwnd)
            if "Cursor" in title:
                windows.append((hwnd, title))
        return True
    
    windows = []
    win32gui.EnumWindows(callback, windows)
    if windows:
        hwnd, title = windows[0]
        logging.info(f"找到Cursor窗口: {title} (句柄: {hwnd})")
        return hwnd
    logging.error("未找到Cursor窗口")
    return None

def activate_cursor_window():
    """激活Cursor窗口"""
    hwnd = find_cursor_window()
    if not hwnd:
        return False
        
    try:
        # 获取当前线程ID
        current_thread = win32api.GetCurrentThreadId()
        # 获取目标窗口线程ID
        target_thread = win32process.GetWindowThreadProcessId(hwnd)[0]
        
        # 附加线程输入
        win32process.AttachThreadInput(current_thread, target_thread, True)
        
        # 确保窗口可见
        if win32gui.IsIconic(hwnd):
            win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
        
        # 将窗口带到前台
        win32gui.BringWindowToTop(hwnd)
        
        # 激活窗口
        win32gui.SetForegroundWindow(hwnd)
        
        # 分离线程输入
        win32process.AttachThreadInput(current_thread, target_thread, False)
        
        # 等待窗口真正激活
        for _ in range(5):  # 最多尝试5次
            if win32gui.GetForegroundWindow() == hwnd:
                logging.info("Cursor窗口已成功激活")
                return True
            time.sleep(0.2)  # 每次等待0.2秒
        
        logging.error("Cursor窗口激活失败")
        return False
        
    except Exception as e:
        logging.error(f"激活Cursor窗口时出错: {str(e)}")
        return False

def send_shortcut():
    """发送Ctrl+Shift+1快捷键"""
    # 按下Ctrl+Shift+1
    win32api.keybd_event(win32con.VK_CONTROL, 0, 0, 0)
    win32api.keybd_event(win32con.VK_SHIFT, 0, 0, 0)
    win32api.keybd_event(0x31, 0, 0, 0)  # 1键的虚拟键码
    
    # 释放按键
    win32api.keybd_event(0x31, 0, win32con.KEYEVENTF_KEYUP, 0)
    win32api.keybd_event(win32con.VK_SHIFT, 0, win32con.KEYEVENTF_KEYUP, 0)
    win32api.keybd_event(win32con.VK_CONTROL, 0, win32con.KEYEVENTF_KEYUP, 0)

def open_in_cursor(file_path, line_number, column=1):
    """通过激活Cursor窗口并发送快捷键来打开文件"""
    try:
        # 确保路径格式正确
        file_path = os.path.normpath(file_path)
        
        # 激活Cursor窗口
        if not activate_cursor_window():
            logging.error("无法激活Cursor窗口")
            return False
            
        # 等待窗口完全激活
        time.sleep(0.5)  # 增加等待时间到1秒
        
        # 发送快捷键
        send_shortcut()
        
        logging.info(f"已在Cursor中打开: {file_path}:{line_number}:{column}")
        return True
    except Exception as e:
        logging.error(f"打开Cursor失败: {str(e)}")
        return False

def open_in_eclipse(file_path, line_number, column=1):
    """通过Eclipse命令行打开文件并跳转行号和列号"""
    try:
        # 确保路径格式正确
        file_path = os.path.normpath(file_path)
        
        # 构建命令行参数
        command = [
            ECLIPSE_PATH,
            "--launcher.openFile",
            f"{file_path}:{line_number}:{column}"
        ]
        
        logging.info(f"正在Eclipse中打开: {file_path}:{line_number}:{column}")
        subprocess.Popen(command, creationflags=subprocess.CREATE_NEW_CONSOLE)
        return True
    except Exception as e:
        logging.error(f"打开Eclipse失败: {str(e)}")
        return False

def on_f4_press():
    """F4按键处理函数"""
    try:
        # 检查两个状态文件是否存在
        cursor_state_exists = os.path.exists(CURSOR_STATE_FILE)
        eclipse_state_exists = os.path.exists(ECLIPSE_STATE_FILE)
        
        if not cursor_state_exists and not eclipse_state_exists:
            logging.error("未找到任何状态文件")
            return
            
        # 获取两个文件的时间戳
        cursor_timestamp = get_file_timestamp(CURSOR_STATE_FILE) if cursor_state_exists else 0
        eclipse_timestamp = get_file_timestamp(ECLIPSE_STATE_FILE) if eclipse_state_exists else 0
        
        # 输出调试信息
        logging.info(f"Cursor状态文件时间戳: {time.ctime(cursor_timestamp)} ({cursor_timestamp})")
        logging.info(f"Eclipse状态文件时间戳: {time.ctime(eclipse_timestamp)} ({eclipse_timestamp})")
        logging.info(f"时间差(秒): {cursor_timestamp - eclipse_timestamp}")
        
        # 根据时间戳决定跳转方向
        if cursor_timestamp > eclipse_timestamp:
            logging.info("从Cursor跳转到Eclipse")
            # 从Cursor跳转到Eclipse
            try:
                with open(CURSOR_STATE_FILE, 'r', encoding='utf-8') as f:
                    current_state = json.load(f)
            except Exception as e:
                logging.error(f"读取Cursor状态文件时出错: {str(e)}")
                return
                
            if not validate_state(current_state):
                return
                
            column = current_state.get("column", 1)
            open_in_eclipse(
                current_state["file_path"],
                current_state["line_number"],
                column
            )
        else:
            logging.info("从Eclipse跳转到Cursor")
            # 从Eclipse跳转到Cursor
            try:
                with open(ECLIPSE_STATE_FILE, 'r', encoding='utf-8') as f:
                    current_state = json.load(f)
            except Exception as e:
                logging.error(f"读取Eclipse状态文件时出错: {str(e)}")
                return
                
            if not validate_state(current_state):
                return
                
            column = current_state.get("column", 1)
            open_in_cursor(
                current_state["file_path"],
                current_state["line_number"],
                column
            )
        
    except Exception as e:
        logging.error(f"处理F4按键时出错: {str(e)}")

def main():
    logging.info("双向跳转器已启动。按F4在Cursor和Eclipse之间切换。")
    
    # 初始检查
    if not check_eclipse_path():
        logging.error("Eclipse路径检查失败。程序退出...")
        return
    
    # 检查Cursor路径
    if not os.path.exists(CURSOR_PATH):
        logging.error(f"未找到Cursor，路径: {CURSOR_PATH}")
        return
    
    # 注册F4按键监听
    keyboard.on_press_key('f4', lambda _: on_f4_press())
    
    # 保持程序运行
    keyboard.wait('esc')  # 按ESC键退出程序

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        logging.info("用户停止了Eclipse跳转器")
    except Exception as e:
        logging.error(f"致命错误: {str(e)}")
    finally:
        keyboard.unhook_all()  # 清理所有按键监听 